package newcrunch.gui;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.text.BadLocationException;
import jsyntaxpane.DefaultSyntaxKit;
import newcrunch.codeanalysis.CodeAnalysisManager;
import newcrunch.grader.AutoTestManager;
import newcrunch.grader.SubmissionInfo;
import newcrunch.grader.SubmissionProcessor;
import newcrunch.gui.multispantable.AttributiveCellTableModel;
import newcrunch.gui.multispantable.MultiSpanCellTable;
import newcrunch.gui.multispantable.TableCellListener;
import newcrunch.gui.tree.CustomTree;
import newcrunch.typography.JavaAnalyzer;
import newcrunch.typography.TypoMainTable;
import newcrunch.util.DisplayHelper;
import newcrunch.util.Logging;
import newcrunch.util.Misc;
import newcrunch.util.PropertyLoader;
import org.antlr.runtime.RecognitionException;
import org.netbeans.swing.tabcontrol.TabDisplayer;
import org.netbeans.swing.tabcontrol.TabbedContainer;

/**
 * Represents a single tab
 * to show a particular student's
 * lab code.
 * 
 * Three steps to add a jsyntaxpane
 * 
 * 1. Add jsyntaxpane jar to classpath
 * 2. Call DefaultSyntaxKit.initKit();
 * 3. Call editor.setContentType("text/java");
 * 
 * @author WL
 */
public class RightTab extends javax.swing.JPanel 
{
    private String language = "text/java";
    
    private String filename = "untitled";
    
    //typography
    private javax.swing.JDialog analysisDialog;
    private TypoMainTable analysisTable;
    private JavaAnalyzer javaAnalyzer;
    private javax.swing.JScrollPane jScrollPane7;
    
    private SwingWorker<Object, Void> analyzeWorker;
    
    //submission info
    private SubmissionInfo submissionInfo;
    
    private boolean displayTotal; //whether to display the total scores in marking scheme
    
    //for interpreting Java as it is typed
    private InterpreterManager interpreterManager;
    
    //to compile the Java code above in order to interpret it
    private CompilerManager compilerManager;
    
    private AutoTestManager autoTestManager;
    
    private CodeAnalysisManager codeAnalysisManager;
    
    static
    {
        DefaultSyntaxKit.initKit();
    }
    
    public RightTab() {
        initComponents();
        
        submitButton.setEnabled(false);
        
        createTypographyComponents();
        
        initTypographyComponents();
        
        multiSpanCellTable.setHorizontalAlignment(SwingConstants.CENTER);
        ToolTipManager.sharedInstance().registerComponent(multiSpanCellTable);
        
        interpreterManager = new InterpreterManager();
        interpreterManager.setRightTab(this);
        
        compilerManager = new CompilerManager();
        compilerManager.setRightTab(this);
        
        autoTestManager = new AutoTestManager();
        autoTestManager.setRightTab(this);
        
        codeAnalysisManager = new CodeAnalysisManager(Misc.getBaseGUI(this));
        codeAnalysisManager.setRightTab(this);
    }
    
    public void setFilename(String name)
    {
        this.filename = name;
    }
    
    public String getFilename()
    {
        return filename;
    }
    
    public NewCrunchEditorPane getEditor()
    {
        return editor;
    }
    
    public JTextArea getCommentsField()
    {
        return gradersComments;
    }
    
    public MultiSpanCellTable getMarkingSchemeTable()
    {
        return multiSpanCellTable;
    }
    
    public void setGraderComments(String text)
    {
        gradersComments.setText(text);
    }
    
    public void setSubmissionInfo(SubmissionInfo info)
    {
        submitButton.setEnabled(true);
        this.submissionInfo = info;
    }
    
    public void setDisplayTotal(boolean val)
    {
        displayTotal = val;
    }
    
    public SubmissionInfo getSubmissionInfo()
    {
        return submissionInfo;
    }
    
    public void setText(String text)
    {
        editor.setText(text);
    }
        
    public String getText()
    {
        return editor.getText();
    }
    
    public void setCaretPosition(int position)
    {
        editor.setCaretPosition(position);
    }
    
    public InterpreterManager getInterpreterManager()
    {
        return interpreterManager;
    }
    
    public JButton getCompileButton()
    {
        return compileButton;
    }
    
    public JTextArea getCompilerOutput()
    {
        return compilerOutputArea;
    }
    
    public JEditorPane getManualTestingPane()
    {
        return manualTestingOutput;
    }
    
    public JScrollPane getManualTestingScrollPane()
    {
        return manualTestingScroll;
    }
    
    public JTextField getTestCasesDisp()
    {
        return testCasesDisp;
    }
    
    public TabbedContainer getAutoTestTabs()
    {
        return autoTestTabs;
    }
    
    public void focusCompileTab()
    {
        bottomPane.setSelectedComponent(testingPanel);
        testPane.setSelectedComponent(compilerPane);
    }
    
    public void focusAutoTestTab()
    {
        bottomPane.setSelectedComponent(testingPanel);
        testPane.setSelectedComponent(autoTestPane);
    }
    
    public String getLanguage()
    {
        return language;
    }
    
    public TabbedContainer getInputTabbedPane()
    {
        return inputTabs;
    }
    
    public TabbedContainer getOutputTabbedPane()
    {
        return outputTabs;
    }
    
    public JButton getTestButton()
    {
        return testButton;
    }
    
    public void configureEditorListener(final CustomTree classList)
    {
        //updates the caret position
        //upon clicking a certain node in the tree
        classList.configureMouseListeners(editor);
        
        //update tree with keytypes
        editor.addKeyListener(new KeyAdapter(){
            SwingWorker<Object, Void> worker;
            @Override
            public void keyReleased(KeyEvent evt)
            {
                if (worker != null)
                    worker.cancel(true);
                
                worker = new SwingWorker<Object, Void>() {
                    @Override
                    protected Object doInBackground() throws Exception {
                        Thread.sleep(CustomTree.TREE_COOLDOWN);
                        
                        if (!this.isCancelled())
                            classList.regenerateTree(editor.getText());
                        return null;
                    }
                };
                
                worker.execute();
            }
        });
    }
    
    private void initTypographyComponents()
    {
        editor.setContentType(language);
        Misc.setIntelligentKeyPair(editor);
        javaAnalyzer = JavaAnalyzer.getInstance();
        
        analysisTable.loadStandards();
        
        editor.setCaretListener(posLabel);
    }
    
    private void createTypographyComponents()
    {
        analysisTable = new TypoMainTable();
        analysisTable.loadStandards();
        jScrollPane7 = new javax.swing.JScrollPane();
        jScrollPane7.setViewportView(analysisTable);
        
        analysisDialog = new javax.swing.JDialog();        
        javax.swing.GroupLayout codeAnalysisLayout = new javax.swing.GroupLayout(analysisDialog.getContentPane());
        analysisDialog.getContentPane().setLayout(codeAnalysisLayout);
        codeAnalysisLayout.setHorizontalGroup(
            codeAnalysisLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane7, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 1017, Short.MAX_VALUE)
        );
        codeAnalysisLayout.setVerticalGroup(
            codeAnalysisLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane7, javax.swing.GroupLayout.DEFAULT_SIZE, 628, Short.MAX_VALUE)
        );
        String title = PropertyLoader.getStringProperty("typomaintable.title");
        analysisDialog.setTitle(title == null ? "Typographical Analysis Results" :
                                              title);
        
        
    }
    
    public void setMarkingScheme(AttributiveCellTableModel scheme)
    {
        multiSpanCellTable.setModel(scheme);
    }
    
    public AttributiveCellTableModel getMarkingScheme()
    {
        return (AttributiveCellTableModel)multiSpanCellTable.getModel();
    }
    
    public String getContentType()
    {
        return language;
    }
    
    public void addTableChangeListener(Action action)
    {
        multiSpanCellTable.addPropertyChangeListener(new TableCellListener(multiSpanCellTable, action));
    }
    
    private String[] getMarksInput()
    {
        TableModel model = multiSpanCellTable.getModel();
        int col = displayTotal ? model.getColumnCount() - 1 : model.getColumnCount();
        String[] result = new String[col];
        int row = model.getRowCount() - 1;
        for (int i = 0; i < col; i++)
        {
            Object val = model.getValueAt(row, i);
            //sets the value to 0 if none is entered
            if (val == null || "".equals(val))
                val = "0";
            //check whether val is a valid number
            Double.parseDouble(val.toString());
            result[i] = val.toString();
        }
        return result;
    }
    
    public void setMarks(String[] marks)
    {
        if (marks == null)
            return;
        
        TableModel model = multiSpanCellTable.getModel();
        int row = model.getRowCount() - 1;
        if (row >= 0)
            for (int i = 0; i < marks.length; i++)
                model.setValueAt(marks[i], row, i);
        
        if (displayTotal)
        {
            double total = 0;
            for (int i = 0; i < marks.length; i++) 
            {
                if (!"".equals(model.getValueAt(row, i)))
                    total += Double.parseDouble(model.getValueAt(row, i).toString());
                else
                    model.setValueAt("0", row, i);
            }       
            model.setValueAt(Misc.DECIMAL_FORMAT.format(total), row, model.getColumnCount() - 1);
        }
    }
    
    private void setTypoData(SubmissionProcessor processor)
    {
        List<String> results = new ArrayList<String>();
        List<String> standardDeviation = new ArrayList<String>();
        List<String> comments = new ArrayList<String>();
        formatTypoData(results, standardDeviation, comments);
        String[] resultsArr = new String[results.size()];
        results.toArray(resultsArr);
        String[] sdArr = new String[standardDeviation.size()];
        standardDeviation.toArray(sdArr);
        String[] commentsArr = new String[comments.size()];
        comments.toArray(commentsArr);
        
        processor.setTypoData(resultsArr, sdArr, commentsArr);
    }
    
    private void formatTypoData(List<String> results, List<String> standardDeviation, List<String>comments)
    {
        try {
            javaAnalyzer.analyze(editor, analysisTable);
            TableModel model = analysisTable.getModel();
            int[] headings = TypoMainTable.subheadingRows;
            for (int i = 0; i < model.getRowCount(); i++)
            {
                //do not send the heading rows
                if (Arrays.binarySearch(headings, i) >= 0)
                    continue;
                
                //do not send the empty rows
                if (model.getValueAt(i, TypoMainTable.RESULTS_COLUMN) == null || 
                        "".equals(model.getValueAt(i, TypoMainTable.RESULTS_COLUMN)))
                    continue;
                
                results.add(model.getValueAt(i, TypoMainTable.RESULTS_COLUMN).toString());
                standardDeviation.add(model.getValueAt(i, TypoMainTable.SD_COLUMN).toString());
                comments.add(model.getValueAt(i, TypoMainTable.COMMENTS_COLUMN).toString());
            }
        }
        catch (BadLocationException e) {
            Logging.log(e);
        }
        catch (RecognitionException e) {
            Logging.log(e);
        }
    }
    
    public void setCompilerOutput(String text)
    {
        compilerOutput.setText(text);
        compilerOutput.setCaretPosition(0);
    }
    
    @Override
    public void firePropertyChange(String propertyName, Object oldValue, Object newValue)
    {
        super.firePropertyChange(propertyName, oldValue, newValue);
    }
    
    public void setAnalysisDialogVisibility(boolean val)
    {
        analysisDialog.setVisible(val);
    }
    
    public void hideDetailDialogs()
    {
        analysisTable.hideAllDialogs();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jSplitPane2 = new javax.swing.JSplitPane();
        jPanel3 = new javax.swing.JPanel();
        submitButton = new javax.swing.JButton();
        bottomPane = new javax.swing.JTabbedPane();
        commentsPanel = new javax.swing.JPanel();
        jSplitPane1 = new javax.swing.JSplitPane();
        jScrollPane2 = new javax.swing.JScrollPane();
        gradersComments = new javax.swing.JTextArea();
        markingSchemePanel = new javax.swing.JPanel();
        multiSpanCellTable = new newcrunch.gui.multispantable.MultiSpanCellTable();
        autoGraderPanel = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        compilerOutput = new javax.swing.JTextArea();
        testingPanel = new javax.swing.JPanel();
        testPane = new javax.swing.JTabbedPane();
        compilerPane = new javax.swing.JScrollPane();
        compilerOutputArea = new javax.swing.JTextArea();
        testCasesInputPane = new javax.swing.JPanel();
        inputTabs = new org.netbeans.swing.tabcontrol.TabbedContainer(TabDisplayer.TYPE_EDITOR);
        testCasesOutputPane = new javax.swing.JPanel();
        outputTabs = new org.netbeans.swing.tabcontrol.TabbedContainer(TabDisplayer.TYPE_EDITOR);
        manualTestingScroll = new javax.swing.JScrollPane();
        manualTestingOutput = new javax.swing.JEditorPane();
        autoTestPane = new javax.swing.JPanel();
        autoTestTabs = new org.netbeans.swing.tabcontrol.TabbedContainer();
        jLabel1 = new javax.swing.JLabel();
        testCasesDisp = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        reportsButton = new javax.swing.JButton();
        compileButton = new javax.swing.JButton();
        posLabel = new javax.swing.JLabel();
        semanticAnalysis = new javax.swing.JButton();
        testButton = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        editor = new newcrunch.gui.NewCrunchEditorPane();

        jSplitPane2.setDividerLocation(336);
        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);

        submitButton.setText("Submit Grading");
        submitButton.setEnabled(false);
        submitButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                submitButtonActionPerformed(evt);
            }
        });

        bottomPane.setTabPlacement(javax.swing.JTabbedPane.BOTTOM);

        jSplitPane1.setDividerLocation(100);
        jSplitPane1.setDividerSize(1);
        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);

        gradersComments.setColumns(20);
        gradersComments.setRows(5);
        jScrollPane2.setViewportView(gradersComments);

        jSplitPane1.setRightComponent(jScrollPane2);

        javax.swing.GroupLayout markingSchemePanelLayout = new javax.swing.GroupLayout(markingSchemePanel);
        markingSchemePanel.setLayout(markingSchemePanelLayout);
        markingSchemePanelLayout.setHorizontalGroup(
            markingSchemePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(multiSpanCellTable, javax.swing.GroupLayout.DEFAULT_SIZE, 626, Short.MAX_VALUE)
        );
        markingSchemePanelLayout.setVerticalGroup(
            markingSchemePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(multiSpanCellTable, javax.swing.GroupLayout.DEFAULT_SIZE, 99, Short.MAX_VALUE)
        );

        jSplitPane1.setLeftComponent(markingSchemePanel);

        javax.swing.GroupLayout commentsPanelLayout = new javax.swing.GroupLayout(commentsPanel);
        commentsPanel.setLayout(commentsPanelLayout);
        commentsPanelLayout.setHorizontalGroup(
            commentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING)
        );
        commentsPanelLayout.setVerticalGroup(
            commentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 195, Short.MAX_VALUE)
        );

        bottomPane.addTab("Mark Allocation and Comments", commentsPanel);

        compilerOutput.setColumns(20);
        compilerOutput.setRows(5);
        jScrollPane3.setViewportView(compilerOutput);

        javax.swing.GroupLayout autoGraderPanelLayout = new javax.swing.GroupLayout(autoGraderPanel);
        autoGraderPanel.setLayout(autoGraderPanelLayout);
        autoGraderPanelLayout.setHorizontalGroup(
            autoGraderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane3, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 628, Short.MAX_VALUE)
        );
        autoGraderPanelLayout.setVerticalGroup(
            autoGraderPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 195, Short.MAX_VALUE)
        );

        bottomPane.addTab("Auto-grading Results", autoGraderPanel);

        compilerOutputArea.setColumns(20);
        compilerOutputArea.setRows(5);
        compilerPane.setViewportView(compilerOutputArea);

        testPane.addTab("Compiler Output", compilerPane);

        javax.swing.GroupLayout testCasesInputPaneLayout = new javax.swing.GroupLayout(testCasesInputPane);
        testCasesInputPane.setLayout(testCasesInputPaneLayout);
        testCasesInputPaneLayout.setHorizontalGroup(
            testCasesInputPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(inputTabs, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        testCasesInputPaneLayout.setVerticalGroup(
            testCasesInputPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(inputTabs, javax.swing.GroupLayout.DEFAULT_SIZE, 167, Short.MAX_VALUE)
        );

        testPane.addTab("Test Cases Input", testCasesInputPane);

        javax.swing.GroupLayout testCasesOutputPaneLayout = new javax.swing.GroupLayout(testCasesOutputPane);
        testCasesOutputPane.setLayout(testCasesOutputPaneLayout);
        testCasesOutputPaneLayout.setHorizontalGroup(
            testCasesOutputPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(outputTabs, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        testCasesOutputPaneLayout.setVerticalGroup(
            testCasesOutputPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(outputTabs, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 167, Short.MAX_VALUE)
        );

        testPane.addTab("Test Cases Output", testCasesOutputPane);

        manualTestingScroll.setViewportView(manualTestingOutput);

        testPane.addTab("Manual Testing", manualTestingScroll);

        jLabel1.setText("Test Cases:");

        testCasesDisp.setEditable(false);
        testCasesDisp.setBorder(null);

        jLabel2.setText("Failed Test Cases: (Derived vs Expected)");

        javax.swing.GroupLayout autoTestPaneLayout = new javax.swing.GroupLayout(autoTestPane);
        autoTestPane.setLayout(autoTestPaneLayout);
        autoTestPaneLayout.setHorizontalGroup(
            autoTestPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(autoTestTabs, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(autoTestPaneLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(autoTestPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(autoTestPaneLayout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(testCasesDisp, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(jLabel2))
                .addContainerGap())
        );
        autoTestPaneLayout.setVerticalGroup(
            autoTestPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, autoTestPaneLayout.createSequentialGroup()
                .addGroup(autoTestPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(testCasesDisp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1))
                .addGap(2, 2, 2)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(autoTestTabs, javax.swing.GroupLayout.DEFAULT_SIZE, 131, Short.MAX_VALUE))
        );

        testPane.addTab("Auto Testing", autoTestPane);

        javax.swing.GroupLayout testingPanelLayout = new javax.swing.GroupLayout(testingPanel);
        testingPanel.setLayout(testingPanelLayout);
        testingPanelLayout.setHorizontalGroup(
            testingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(testPane)
        );
        testingPanelLayout.setVerticalGroup(
            testingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(testPane)
        );

        bottomPane.addTab("Test Cases", testingPanel);

        reportsButton.setText("Typographical Analysis");
        reportsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                reportsButtonActionPerformed(evt);
            }
        });

        compileButton.setText("Compile");

        posLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        posLabel.setText("1:1 (0)");
        posLabel.setToolTipText("row:col (character)");

        semanticAnalysis.setText("Semantic Analysis");
        semanticAnalysis.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                semanticAnalysisActionPerformed(evt);
            }
        });

        testButton.setText("Run Tests");

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(submitButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(reportsButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(compileButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(testButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(semanticAnalysis)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(posLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addComponent(bottomPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(submitButton)
                        .addComponent(reportsButton)
                        .addComponent(compileButton)
                        .addComponent(semanticAnalysis)
                        .addComponent(testButton))
                    .addComponent(posLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(bottomPane))
        );

        bottomPane.getAccessibleContext().setAccessibleName("");

        jSplitPane2.setRightComponent(jPanel3);

        jScrollPane1.setViewportView(editor);

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 335, Short.MAX_VALUE)
        );

        jSplitPane2.setLeftComponent(jPanel1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane2)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSplitPane2)
        );
    }// </editor-fold>//GEN-END:initComponents

    private boolean hasEmptyCell(DefaultTableModel model) 
    {
        if (model == null)
            return false;
        
        for (int j = 0; j < model.getColumnCount(); j++)
            if (model.getValueAt(model.getRowCount() - 1, j) == null || 
                    "".equals(model.getValueAt(model.getRowCount() - 1, j).toString().trim()))
                    return true;
        return false;
    }
    
    private void submitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_submitButtonActionPerformed
        String message = "Are you sure you want to submit your grading?";
        
        if ("".equals(gradersComments.getText()))
            message += "\nYou did not provide any comments for the student's work.";
        
        if (hasEmptyCell(getMarkingScheme()))
            message += "\nThere are empty fields in the scores table.";
        
        if (DisplayHelper.showConfirmFrame(this, "Submit Grading Confirmation", message) !=
                JOptionPane.OK_OPTION)
            return;
        
        final JDialog dialog = DisplayHelper.getProgressFrame(RightTab.this, "Sending submission", "Sending grading comment", true);
        DisplayHelper.centralizePosition(dialog, this);
        dialog.setVisible(true);
        dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
                    
        new SwingWorker<Object, Void>(){
            @Override
            protected Object doInBackground() {
                try {                                        
                    SubmissionProcessor process = new SubmissionProcessor();
                    process.setMarks(getMarksInput());                    
                    process.setGradedCode(editor.getText());
                    process.setGraderComments(gradersComments.getText());
                    setTypoData(process);
                    process.sendSubmission(Misc.getBaseGUI(RightTab.this).getAuthManager().getConnectionManager(), submissionInfo.submissionId, submissionInfo.filename);
                } catch (UnsupportedEncodingException e) {
                    Logging.log(e);
                } catch (IOException e) {
                    Logging.log(e);
                    DisplayHelper.showErrorFrame(RightTab.this, "Connection Error", "Unable to connect to server");
                }
                dialog.setVisible(false);
                DisplayHelper.showInfoFrame(RightTab.this, "Submission Success", "Grading report successfully submitted.");
                
                //updates the submissions list
                RightTab.this.firePropertyChange("updateSubmissions", null, null);
                
                //and the submissions info
                RightTab.this.firePropertyChange("updateSubmissionInfo", null, null);
                
                //reset the modified status
                RightTab.this.firePropertyChange("reset", null, null);
                
                //select the graded file in the graded list
                RightTab.this.firePropertyChange("selectInPanel", null, submissionInfo);
                return null;
            }
        }.execute();
        
    }//GEN-LAST:event_submitButtonActionPerformed

    private void reportsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reportsButtonActionPerformed
        if (analyzeWorker == null || analyzeWorker.isDone())
        {
            analyzeWorker = new SwingWorker<Object, Void> () {
                @Override
                protected Object doInBackground() throws Exception {
                    String msg = "Processsing Source Code...";
                    JDialog loadingFrame = DisplayHelper.getProgressFrame(RightTab.this, msg, msg, true);
                    DisplayHelper.centralizePosition(loadingFrame, RightTab.this);
                    loadingFrame.setVisible(true);
                    try {
                        javaAnalyzer.analyze(editor, analysisTable);
                        analysisTable.revalidate();
                        analysisTable.repaint();
                    }
                    catch (BadLocationException e) {
                        Logging.log(e);
                    }
                    catch (RecognitionException e) {
                        Logging.log(e);
                    }

                    analysisDialog.pack();
                    analysisDialog.setVisible(true);
                    loadingFrame.setVisible(false);
                    loadingFrame.dispose();
                    
                    return null;
                }
           };
           analyzeWorker.execute();
        }
    }//GEN-LAST:event_reportsButtonActionPerformed
    
    private void semanticAnalysisActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_semanticAnalysisActionPerformed
        codeAnalysisManager.runAnalysis();
    }//GEN-LAST:event_semanticAnalysisActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel autoGraderPanel;
    private javax.swing.JPanel autoTestPane;
    private org.netbeans.swing.tabcontrol.TabbedContainer autoTestTabs;
    private javax.swing.JTabbedPane bottomPane;
    private javax.swing.JPanel commentsPanel;
    private javax.swing.JButton compileButton;
    private javax.swing.JTextArea compilerOutput;
    private javax.swing.JTextArea compilerOutputArea;
    private javax.swing.JScrollPane compilerPane;
    private newcrunch.gui.NewCrunchEditorPane editor;
    private javax.swing.JTextArea gradersComments;
    private org.netbeans.swing.tabcontrol.TabbedContainer inputTabs;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JEditorPane manualTestingOutput;
    private javax.swing.JScrollPane manualTestingScroll;
    private javax.swing.JPanel markingSchemePanel;
    private newcrunch.gui.multispantable.MultiSpanCellTable multiSpanCellTable;
    private org.netbeans.swing.tabcontrol.TabbedContainer outputTabs;
    private javax.swing.JLabel posLabel;
    private javax.swing.JButton reportsButton;
    private javax.swing.JButton semanticAnalysis;
    private javax.swing.JButton submitButton;
    private javax.swing.JButton testButton;
    private javax.swing.JTextField testCasesDisp;
    private javax.swing.JPanel testCasesInputPane;
    private javax.swing.JPanel testCasesOutputPane;
    private javax.swing.JTabbedPane testPane;
    private javax.swing.JPanel testingPanel;
    // End of variables declaration//GEN-END:variables
}
